package org.liaohailong.library.db.builder

import android.content.ContentValues
import android.text.TextUtils
import org.liaohailong.library.db.annotation.Column
import org.liaohailong.library.db.model.ColumnInfo
import org.liaohailong.library.db.model.KeyValueInfo
import org.liaohailong.library.db.util.Utility

/**
 * Author: liaohailong
 * Date: 2019/4/3
 * Time: 4:13 PM
 * Description: SQL接口适配器
 **/
abstract class AbSQLHelper : SQLHelper {
    private var dataBaseName = ""
    private var tableName = ""
    private var tablePrimaryKey = "id"
    private val selectColumns: MutableList<String> = mutableListOf()
    private val columns: MutableList<ColumnInfo> = mutableListOf()
    private val insertParams: MutableList<KeyValueInfo> = mutableListOf()
    private val whereParams: MutableList<KeyValueInfo> = mutableListOf()
    private val orderParams: MutableList<KeyValueInfo> = mutableListOf()
    private var limit: Int = 0
    private var offset: Int = 0

    override fun saveItem(table: Any) {
        for (declaredField in table.javaClass.declaredFields) {
            declaredField.getAnnotation(Column::class.java)?.takeIf { !it.primaryKey }?.apply {
                declaredField.isAccessible = true
                val key = if (TextUtils.isEmpty(name)) declaredField.name else name
                val value = declaredField.get(table)
                insertParams.add(KeyValueInfo(key, value.toString()))
            }
        }
    }

    override fun putUpdateParam(key: String, value: Any) {
        insertParams.add(KeyValueInfo(key, value.toString()))
    }

    override fun putWhereParam(key: String, value: Any) {
        whereParams.add(KeyValueInfo(key, value.toString()))
    }

    override fun putOrder(name: String) {
        orderParams.add(KeyValueInfo(name, ""))
    }

    override fun putLimit(limit: Int, offset: Int) {
        this.limit = limit
        this.offset = offset
    }

    override fun setDataBaseName(dbName: String) {
        dataBaseName = dbName
    }

    override fun getDataBaseName(): String {
        return dataBaseName
    }

    override fun setTable(table: Class<*>) {
        val tableInfo = Utility.getTableInfo(table)
        tableName = tableInfo.name
        tablePrimaryKey = tableInfo.primaryKey
        columns.clear()
        columns.addAll(tableInfo.columns)
    }

    override fun getTable(): String {
        return tableName
    }

    override fun getPrimaryKey(): String {
        return tablePrimaryKey
    }

    override fun setSelectColumns(distinct: List<String>) {
        this.selectColumns.clear()
        this.selectColumns.addAll(distinct)
    }

    override fun getSelectColumns(): List<String>? {
        if (selectColumns.isEmpty()) return null
        val result = mutableListOf<String>()
        for (name in selectColumns) {
            for (column in getAllColumns()) {
                if (TextUtils.equals(column.name, name)) result.add(name)
            }
        }
        return if (result.isEmpty()) null else result
    }

    override fun getAllColumns(): List<ColumnInfo> {
        return columns
    }

    private val contentValues = ContentValues()
    override fun getContentValues(): ContentValues? {
        if (insertParams.isEmpty()) return null
        contentValues.clear()
        for (insertParam in insertParams) {
            when (insertParam.value) {
                is Int -> contentValues.put(insertParam.name, insertParam.value)
                is Long -> contentValues.put(insertParam.name, insertParam.value)
                is Float -> contentValues.put(insertParam.name, insertParam.value)
                is Double -> contentValues.put(insertParam.name, insertParam.value)
                is String -> contentValues.put(insertParam.name, insertParam.value)
                else -> contentValues.put(insertParam.name, insertParam.value.toString())
            }
        }
        return contentValues
    }

    override fun getWhereClause(): String {
        val sql = StringBuilder()
        val notEmpty = whereParams.isNotEmpty()
        for (keyValueInfo in whereParams) {
            sql.append(" ").append(keyValueInfo.name).append("=?")
            sql.append(" AND ")
        }
        if (notEmpty) sql.delete(sql.length - " AND ".length, sql.length)
        return sql.toString()
    }

    override fun getWhereArgs(): Array<String> {
        val args: MutableList<String> = mutableListOf()
        for (whereParam in whereParams) {
            args.add(whereParam.value.toString())
        }
        return args.toTypedArray()
    }

    override fun getOrderBy(orderBy: String): String? {
        if (orderParams.isEmpty()) return null
        val sql = StringBuilder()
        orderParams.forEach { sql.append(" ").append(it.name).append(",") }
        sql.deleteCharAt(sql.length - 1)
        sql.append(" ").append(orderBy).append(" ")
        return sql.toString()
    }

    override fun getLimit(): String? {
        limit = Math.max(0, limit)
        offset = Math.max(0, offset)

        val sql = StringBuilder()
        when {
            limit == 0 && offset == 0 -> return null
            limit > 0 && offset == 0 -> sql.append(" ").append(limit).append(" ")
            limit > 0 && offset > 0 -> {
                sql.append(" ").append(offset).append(" ")
                sql.append(",").append(limit).append(" ")
            }
        }
        return if (TextUtils.isEmpty(sql.toString())) null else sql.toString()
    }

    override fun reset() {
        tableName = ""
        tablePrimaryKey = "id"
        columns.clear()
        insertParams.clear()
        whereParams.clear()
        orderParams.clear()
        limit = 0
        offset = 0
    }
}